package joc.internal.transformer;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import javassist.ClassPool;
import javassist.CtBehavior;
import javassist.CtClass;
import javassist.CtMethod;
import joc.customize.Contract;
import joc.customize.ForMethodEvaluateAtEndOfMethodAndInherit;

public class PostConditionMethodTransformer extends DeclaredMethodTransformer {

	public PostConditionMethodTransformer(ClassPool pool) {
		super(pool);
	}

	@Override
	public void transform(CtClass clazz, CtMethod method) throws Exception {
		logger.debug("method " + method.getLongName());
		for (CtBehavior consultedBehavior : getConsultedBehaviors(method)) {
			logger.info("consulted behavior " + consultedBehavior.getLongName());
			for (Class<? extends Annotation> contractAnnotation : Transformer.getContractMap().keySet()) {
				Annotation annotation = (Annotation) consultedBehavior.getAnnotation(contractAnnotation);
				if (annotation != null) {
					logger.info("method " + method.getLongName() + " has contract "
							+ Transformer.getContractMap().get(contractAnnotation).getClass().getName());
					applyContract(method, Transformer.getContractMap().get(contractAnnotation), annotation);
				}
			}
		}
	}

	private void applyContract(CtMethod method, Contract contract, Annotation annotation) throws Exception {
		for (Method contractMethod : getContractMethodsWithAnnotation(contract,
				ForMethodEvaluateAtEndOfMethodAndInherit.class)) {
			String returnValue = handlePrimitive(contractMethod.getParameterTypes()[1], "$_");
			method.insertAfter(getContractCallString(contractMethod, contract, annotation, true,
					"(" + contractMethod.getParameterTypes()[1].getName() + ") " + returnValue));
			logger.info("inserted " + contract.getClass().getName() + " in method " + method.getLongName());
		}
	}

}
